/*******************************************************************************************
 *      @name   getweather.c
 *      @brief  获取天气发送巴法云
 *      @date   2025/02/26
 *      @author cecelmx@126.com
 *      @note
 *              1.HTTP协议是基于请求/响应模式，而且HTTP服务有独立的端口号，HTTP服务的端口号是80
 *              2.心知天气服务器提供的API接口地址
 *               /v3/weather/now.json?key=your_api_key&location=beijing&language=en&unit=c
 *
 *              3.心知天气最好是使用gethostbyname来进行域名的解析，得到服务器地址116.62.81.138
 *
 *              4.心知天气返回的响应体是JSON格式，并且需要把APIKEY更为自己的密钥
 *
 *      @version  xx.xx.xx   主版本号.次版本号.修正版本号
 *
 *      CopyRight (c)   2024-2025   Your Name     All Right Reserved
 *
 * ****************************************************************************************/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <netdb.h>
#include <sys/ipc.h>
#include <sys/msg.h>

// 缓冲区大小
#define BUFSIZE 1024

// 心知天气API的密钥，需要修改为自己的密钥
#define API_KEY "S-A6DrAZRYYsDnkVh"

// HTTP服务的端口
#define HTTP_PORT 80

// 聚合API的URL
#define SERVER_URL "/v3/weather/now.json"

// 聚合API的IP
#define SERVER_IP "116.62.81.138"

// 聚合API的域名
#define SERVER_DOMAIN "api.seniverse.com"

typedef struct weather
{
    int temp;
} weather_t, *weather_p;

typedef struct msgbuf
{
    long mtype;
    weather_t weather_data;
} msg_t, *msg_p;

int queue_id = 0;

/**************************************************************************
 * @name: create_queue
 * @brief: 创建消息队列
 * @note: None
 * @retval: None
 **************************************************************************/
void create_queue(void)
{
    queue_id = msgget(ftok(".", 1), IPC_CREAT | 0666);
    if (queue_id == -1)
    {
        fprintf(stderr, "创建队列失败,error=%d,%s\n", errno, strerror(errno));
    }
    printf("创建的队列ID:%d\n", queue_id);
}

/**************************************************************************
 * @name: send_msg
 * @brief: 往消息队列发送消息
 * @note: None
 * @retval: None
 **************************************************************************/
void send_msg(int temp)
{
    msg_p msg_data = (msg_p)calloc(1, sizeof(msg_t));

    msg_data->mtype = 1;
    msg_data->weather_data.temp = temp;
    msgsnd(queue_id, msg_data, sizeof(weather_t), IPC_NOWAIT);
    printf("1秒发送了一次\n");
    free(msg_data);
    sleep(1);
}

int main(int argc, char **argv)
{
    char recvbuf[BUFSIZE] = {0}; // 存储响应内容
    char request[BUFSIZE] = {0}; // 存储请求内容
    create_queue();

    // 1.创建TCP套接字,HTTP协议是基于TCP协议实现的
    int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == tcp_socket)
    {
        fprintf(stderr, "create tcp socket error,%s\n", strerror(errno));
        exit(-1);
    }

    // 2.向心知天气API的服务器发起连接请求
    struct sockaddr_in dest = {0};               // IPv4地址格式的实例
    dest.sin_family = AF_INET;                   // IPv4协议族
    dest.sin_port = htons(HTTP_PORT);            // 目标端口，需要转换为网络字节序
    dest.sin_addr.s_addr = inet_addr(SERVER_IP); // 目标地址，需要转换为网络字节序

    if (-1 == connect(tcp_socket, (struct sockaddr *)&dest, sizeof(dest)))
    {
        fprintf(stderr, "connect error,%s\n", strerror(errno));
        exit(-2);
    }

    printf("connect ok\n");

    for (;;)
    {
        // 3.连接成功后，可以向服务器发起请求，需要构造请求内容
        char local[64] = {0};
        memset(request, 0, BUFSIZE); // 清空接收缓冲区
        printf("请输入城市名称(拼音，例如Beijing):");
        scanf("%s", local);

        sprintf(request, "GET %s?key=%s&location=%s&language=en&unit=c HTTP/1.1\r\n"
                         "Host: %s\r\n"
                         "\r\n",
                SERVER_URL, API_KEY, local, SERVER_DOMAIN);
        // 4.发送请求
        send(tcp_socket, request, strlen(request), 0); // 向聚合API服务器发送请求
        printf("send ok\n");

        // 5.等待心知天气API的响应内容  先返回响应头部,再返回响应Body
        while (!strstr(recvbuf, "{"))
        {
            recv(tcp_socket, recvbuf, sizeof(recvbuf), 0); // 读取数据，默认会阻塞
        }

        printf("%s\n", recvbuf);
        const char delim[] = ":\"";
        char *field = strtok(recvbuf, delim);
        int temp = 0;
        while (field != NULL)
        {
            field = strtok(NULL, delim); // 获取下一个标记
            if (!strcmp(field, "temperature"))
            {
                field = strtok(NULL, delim); // 获取温度的数值
                temp = atoi(field);
                break;
            }
        }
        printf("temp:%d\n", temp);
        send_msg(temp);
        memset(recvbuf, 0, BUFSIZE); // 清空接收缓冲区
    }

    return 0;
}
